#include "co_async/and_then.hpp"
#include "co_async/async_loop.hpp"
#include "co_async/debug.hpp"
#include "co_async/epoll_loop.hpp"
#include "co_async/filesystem.hpp"
#include "co_async/generator.hpp"
#include "co_async/limit_timeout.hpp"
#include "co_async/simple_map.hpp"
#include "co_async/socket.hpp"
#include "co_async/stdio.hpp"
#include "co_async/stream.hpp"
#include "co_async/task.hpp"
#include "co_async/timer_loop.hpp"
#include "co_async/when_all.hpp"
#include "co_async/when_any.hpp"
#include <algorithm>
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <vector>

using namespace std::literals;
using namespace co_async;

AsyncLoop loop;

struct HTTPHeaders : SimpleMap<std::string, std::string> {
  using SimpleMap<std::string, std::string>::SimpleMap;
};

struct HTTPRequest {
  std::string method;
  std::string uri;
  HTTPHeaders headers;
  std::string body{};

  Task<> write_into(auto &sock) {
    co_await sock.puts(method);
    co_await sock.putchar(' ');
    co_await sock.puts(uri);
    co_await sock.puts(" HTTP/1.1\r\n"sv);
    for (auto const &[k, v] : headers) {
      co_await sock.puts(k);
      co_await sock.puts(": "sv);
      co_await sock.puts(v);
      co_await sock.puts("\r\n"sv);
    }
    if (body.empty()) {
      co_await sock.puts("\r\n"sv);
    } else {
      co_await sock.puts("content-length: "sv);
      co_await sock.puts(std::to_string(body.size()));
      co_await sock.puts("\r\n"sv);
      co_await sock.puts(body);
    }
  }

  auto repr() const { return std::make_tuple(method, uri, headers, body); }
};

struct HTTPResponse {
  int status;
  HTTPHeaders headers;
  std::string body{};

  Task<> read_from(auto &sock) {
    auto line = co_await sock.getline("\r\n"sv);
    if (line.size() <= 9 || line.substr(0, 9) != "HTTP/1.1 "sv) [[unlikely]] {
      throw std::invalid_argument("invalid http response");
    }
    status = std::stoi(line.substr(9));
    while (true) {
      auto line = co_await sock.getline("\r\n"sv);
      if (line.empty()) {
        break;
      }
      auto pos = line.find(':');
      if (pos == line.npos || pos == line.size() - 1 || line[pos + 1] != ' ')
          [[unlikely]] {
        throw std::invalid_argument("invalid http response");
      }
      auto key = line.substr(0, pos);
      for (auto &c : key) {
        if (c >= 'A' && c <= 'Z') {
          c += 'a' - 'A';
        }
      }
      headers.insert_or_assign(std::move(key), line.substr(pos + 2));
    }
    if (auto p = headers.at("content-length"sv)) [[likely]] {
      auto len = std::stoi(*p);
      body = co_await sock.getn(len);
    }
  }

  auto repr() const { return std::make_tuple(status, headers, body); }
};

// Task<> amain() {
//     debug(), "开始连接";
//     auto addr = socket_address(ip_address("142857.red"), 8080);
//     debug(), "连接到", addr.mAddr.ss_family;
//     FileStream sock(loop, co_await create_tcp_client(loop, addr));

//     HTTPRequest request{
//         .method = "GET",
//         .uri = "/api/tts?text=小彭老师真好",
//         .headers =
//             {
//                 {"host", "142857.red:8080"},
//                 {"user-agent", "co_async"},
//                 {"connection", "keep-alive"},
//             },
//     };
//     co_await request.write_into(sock);
//     co_await sock.flush();

//     HTTPResponse response;
//     co_await response.read_from(sock);

//     FileStream file(
//         loop, co_await open_fs_file(loop, "/tmp/output.wav",
//         OpenMode::Write));
//     co_await file.puts(response.body);
//     co_await file.flush();
// }

Task<> amain() {
  debug(), "开始连接到 httpbin.org";

  try {
    // 连接到 httpbin.org (一个公共的HTTP测试服务)
    auto addr = socket_address(ip_address("httpbin.org"), 80);
    debug(), "连接地址已创建";

    FileStream sock(loop, co_await create_tcp_client(loop, addr));
    debug(), "TCP连接已建立";

    // 发送一个简单的GET请求
    HTTPRequest request{
        .method = "GET",
        .uri = "/get?test=hello",
        .headers =
            {
                {"host", "httpbin.org"},
                {"user-agent", "co_async/1.0"},
                {"connection", "close"},
                {"accept", "application/json"},
            },
    };

    debug(), "发送HTTP请求";
    co_await request.write_into(sock);
    co_await sock.flush();

    debug(), "读取HTTP响应";
    HTTPResponse response;
    co_await response.read_from(sock);

    debug(), "HTTP状态码:", response.status;

    // 打印响应信息
    std::cout << "=== HTTP Response ===" << std::endl;
    std::cout << "Status: " << response.status << std::endl;
    std::cout << "Headers:" << std::endl;
    for (auto const &[key, value] : response.headers) {
      std::cout << "  " << key << ": " << value << std::endl;
    }
    std::cout << "Body length: " << response.body.size() << std::endl;
    std::cout << "Body content:" << std::endl;
    std::cout << response.body << std::endl;

    // // 可选：将响应保存到文件
    // if (!response.body.empty()) {
    //   FileStream file(loop,
    //                   co_await open_fs_file(loop, "/tmp/http_response.json",
    //                                         OpenMode::Write));
    //   co_await file.puts(response.body);
    //   co_await file.flush();
    //   debug(), "响应已保存到 /tmp/http_response.json";
    // }

  } catch (std::exception const &e) {
    std::cerr << "错误: " << e.what() << std::endl;
  }

  debug(), "amain() 函数完成";
}

int main() {
  run_task(loop, amain());
  return 0;
}
